#if defined(_MSC_VER)
#pragma once
#endif

#ifndef LM_CORE_FILTER_H
#define LM_CORE_FILTER_H


#include "lm.h"
#include "memory.h"

#define FILTER_TABLE_SIZE 16

class Filter : public ReferenceCounted
{
public:
	Filter(float xw, float yw) 
		: xWidth(xw), yWidth(yw), invXWidth(1.f/xw), invYWidth(1.f/yw){
	}
	~Filter()
	{
		//if(filterTable) delete [] filterTable;
		SAFE_DELETE_ARRAY(filterTable);
	}
	float xWidth, yWidth, invXWidth, invYWidth;
	virtual float Weight(float x, float y) const = 0;
	virtual void ComputeFilterTable() const = 0;
	// filter table
	mutable float *filterTable; 
private:
};

class BoxFilter : public Filter
{
public:
	BoxFilter(float xw = 0.5f, float yw = 0.5f) : Filter(xw, yw)
	{
		ComputeFilterTable();
	}
	~BoxFilter();
	float Weight(float x, float y) const;
	void ComputeFilterTable() const;
};

class TriangleFilter : public Filter
{
public:
	TriangleFilter(float xw = 2.f, float yw = 2.f) : Filter(xw, yw)
	{
		ComputeFilterTable();
	}
	~TriangleFilter();
	float Weight(float x, float y)const;
	void ComputeFilterTable() const;
};

class GaussianFilter : public Filter
{
public:
	GaussianFilter(float xw = 2.f, float yw = 2.f, float a = 2.f) : Filter(xw, yw)
	{
		alpha = a;
		expX = expf(-alpha * xWidth * xWidth);
		expY = expf(-alpha * yWidth * yWidth);
		ComputeFilterTable();
	}
	~GaussianFilter();
	float Weight(float x, float y) const;
	void ComputeFilterTable() const;
private:
	float alpha;
	float expX, expY;
};

class MitchellFilter : public Filter
{
public:
	// B + 2C = 1 is recommend
	MitchellFilter(float b = 1.f/3, float c = 1.f/3, float xw = 2.f, float yw = 2.f) : Filter(xw, yw)
	{
		B = b;
		C = c;
		ComputeFilterTable();
	}
	~MitchellFilter();
	float Weight(float x, float y) const;
	float Mitchell1D(float x) const;
	void ComputeFilterTable() const;
private:
	float B, C;
};

class LanczosSincFilter : public Filter
{
public:
	// tau = 3, for example
	LanczosSincFilter(float xw = 4.f, float yw = 4.f, float t = 3): Filter(xw, yw)
	{
		tau = t;
		ComputeFilterTable();
	}
	~LanczosSincFilter();
	float Weight(float x, float y) const;
	float Sinc1D(float x) const;
	void ComputeFilterTable() const;
private:
	float tau;
};

#endif	// LM_CORE_FILTER_H